package com.zdkj.subway.st.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.util.DateUtils;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.fill.FillConfig;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zdkj.common.core.util.R;
import com.zdkj.common.core.util.SpringContextHolder;
import com.zdkj.common.security.service.PigxUser;
import com.zdkj.common.security.util.SecurityUtils;
import com.zdkj.subway.st.constant.enums.StockEnum;
import com.zdkj.subway.st.dto.in.SwOutExportExcelDTO;
import com.zdkj.subway.st.dto.in.SysDictItemDTO;
import com.zdkj.subway.st.dvo.SwPmTicketAreaDvo;
import com.zdkj.subway.st.dvo.SwPmTicketCardTypeDvo;
import com.zdkj.subway.st.dvo.SwPmTicketCardTypeParamDvo;
import com.zdkj.subway.st.dvo.SwStOuputDetailExcelDvo;
import com.zdkj.subway.st.entity.SwStOutputDetail;
import com.zdkj.subway.st.entity.SwStStockDayCheckDetail;
import com.zdkj.subway.st.fegin.SubwaySupportService;
import com.zdkj.subway.st.mapper.SwStOutputDetailMapper;
import com.zdkj.subway.st.mapper.SwStStockDayCheckDetailMapper;
import com.zdkj.subway.st.service.SwStOutputDetailService;
import com.zdkj.subway.st.util.GenSerialNo;
import com.zdkj.subway.st.util.LocalDateConverter;
import com.zdkj.subway.st.util.LocalDateTimeConverter;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.net.URLEncoder;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @ProjectName: zdkj
 * @Package: com.zdkj.subway.st.service.impl
 * @ClassName: SwStOutputDetailServiceImpl
 * @Description:
 * @Author: kangjian
 * @CreateDate: 2020/1/11 9:03
 * @Version: 1.0
 */
@Service
@AllArgsConstructor
@Slf4j
public class SwStOutputDetailServiceImpl extends ServiceImpl<SwStOutputDetailMapper, SwStOutputDetail> implements SwStOutputDetailService {

    @Autowired
    private SwStStockDayCheckDetailServiceImpl sdcd;

    @Autowired
    private GenSerialNo genSerialNo;

    @Autowired
    private SubwaySupportService subwaySupportService;

    @Resource
    private SwStStockDayCheckDetailMapper stStockDayCheckDetailMapper;


//    @Resource(name = "invoiceSequence")
//    private Sequence invoiceSequence;

    @Override
    public boolean applyedBatch(List<Integer> ids) {
        Collection<SwStOutputDetail> swStOutputDetail = listByIds(ids);
        for (SwStOutputDetail item : swStOutputDetail) {
            if("1".equals(item.getCheckApproveStatus())||
                    "4".equals(item.getCheckApproveStatus())){
                item.setCheckApproveStatus("2");
            }
        }
        return updateBatchById(swStOutputDetail);
    }
    @Override
    public boolean approvedBatch(List<Integer> ids) {
        Collection<SwStOutputDetail> swStOutputDetail = listByIds(ids);
        for (SwStOutputDetail item : swStOutputDetail) {
            if("2".equals(item.getCheckApproveStatus())){
                item.setCheckApproveStatus("3");
            }
        }
        return updateBatchById(swStOutputDetail);
    }


    @Transactional
    public R saveNew(SwStOutputDetail swStOutputDetail) {
        String errorMessage = "更新之后会存在结存数量小于当前车票数量，不允许修改！";
        String errorMessage2 = "库存更新异常！";
        boolean issuccuess = true;
        //首先更新库存账
        SwStStockDayCheckDetail swStStockDayCheckDetail = new SwStStockDayCheckDetail();
        try {
            ////统计最新库存量
            //int settleNum = this.getSettleNum(swStOutputDetail);
            //根据车票名称和库区，找到最大的id号对应的结存数量
            int settleNum = sdcd.getNewSettleNum(swStOutputDetail.getTicketName(), swStOutputDetail.getStockArea());
            if((settleNum - swStOutputDetail.getTicketNumber())<0){
                throw  new Exception(errorMessage);
            }
            String outputstorage = "出库";
            setSwStStockDayCheckDetail(swStStockDayCheckDetail,swStOutputDetail,outputstorage);
            //更新库存量
            swStStockDayCheckDetail.setStorageNumber(swStOutputDetail.getTicketNumber());
            //结存数量-出库数量 = 新的结存数量。
            swStStockDayCheckDetail.setSettleNumber(settleNum - swStOutputDetail.getTicketNumber());
            issuccuess = sdcd.save(swStStockDayCheckDetail);
            if (!issuccuess) {
                issuccuess = false;
                throw  new Exception(errorMessage2);
            }
            //设置关联库存id
            swStOutputDetail.setStockdayid(swStStockDayCheckDetail.getId());
            //出库生成单号和更新基础表信息
            outputGenerateSingle(swStOutputDetail);
            issuccuess = issuccuess && super.save(swStOutputDetail);
            QueryWrapper<SwStStockDayCheckDetail> wrapper = new QueryWrapper<>();
            wrapper.lambda().eq(SwStStockDayCheckDetail::getId,swStOutputDetail.getStockdayid());
            SwStStockDayCheckDetail stockDayCheckDetail = new SwStStockDayCheckDetail();
            stockDayCheckDetail.setOutputOrInputStockid(swStOutputDetail.getId());
            stockDayCheckDetail.setOutputOrInputStockno(swStOutputDetail.getOutstockno());
            sdcd.update(stockDayCheckDetail,wrapper);
            SwTkOutStockReceive swTkOutStockReceive = SpringContextHolder.getBean(SwTkOutStockReceive.class);
            issuccuess = issuccuess && swTkOutStockReceive.saveTicketReceiveInfo(swStOutputDetail);

        }  catch (Exception e) {
            e.printStackTrace();
            //设置手动回滚
            TransactionAspectSupport.currentTransactionStatus()
                    .setRollbackOnly();
            return R.failed(e.getMessage().equals(errorMessage) || e.getMessage().equals(errorMessage2)? e.getMessage() : "系统错误请联系管理员！");
        }
        return R.ok(issuccuess);
    }

    /**
     * 出库生成单号和更新基础表信息
     * @param swStOutputDetail
     */
    public void outputGenerateSingle(SwStOutputDetail swStOutputDetail) {
        //其次更新入库基础表
        PigxUser user = SecurityUtils.getUser();
        swStOutputDetail.setCreatorName(user.getUsername());
        swStOutputDetail.setCreatorId(user.getId());
        //所有出库信息默认为否
        swStOutputDetail.setIsreceive("否");
        //其他关联方式入库，不需要重新设置流水号
        if (StringUtils.isEmpty(swStOutputDetail.getOutstockno())) {
            //根据票种生成单号前缀
            String prefix = genSerialNo.getPreFixByTicketType(swStOutputDetail.getTicketType());
            String serialno = genSerialNo.genSerioNo(StockEnum.StockType.OUTSTOCK.getValue());
            swStOutputDetail.setOutstockno(prefix+serialno);
        }
    }

    private void setSwStStockDayCheckDetail(SwStStockDayCheckDetail swStStockDayCheckDetail, SwStOutputDetail swStOutputDetail, String storage) {
        //设置票种
        swStStockDayCheckDetail.setTicketType(swStOutputDetail.getTicketType());
        //车票名称
        swStStockDayCheckDetail.setTicketName(swStOutputDetail.getTicketName());
        //车票次数
        swStStockDayCheckDetail.setTicketTimes(swStOutputDetail.getTicketTimes());
        //车票金额
        swStStockDayCheckDetail.setTicketPrice(swStOutputDetail.getTicketPrice());
        //设置出库类型
        swStStockDayCheckDetail.setStorageType(storage);
        //设置流动后库存
        swStStockDayCheckDetail.setStockArea(swStOutputDetail.getStockArea());
        //todo 反查出库类型
        String outGoingTypeName = stStockDayCheckDetailMapper.getOutGoningType(swStOutputDetail.getOutGoingType());
        swStStockDayCheckDetail.setOutInGoingType(outGoingTypeName);
        //出库时间
        swStStockDayCheckDetail.setOutInGoingTime(swStOutputDetail.getOutGoingTime());
        //车票有效期
        swStStockDayCheckDetail.setActiveTime(swStOutputDetail.getActiveTime());
        //车票最晚启动日期
        swStStockDayCheckDetail.setLatestStartTime(swStOutputDetail.getLatestStartTime());
        //库管员1工号
        swStStockDayCheckDetail.setKeeper1code(swStOutputDetail.getKeeper1code());
        //库管员1
        swStStockDayCheckDetail.setKeeper1name(swStOutputDetail.getKeeper1name());
        //库管员2工号
        swStStockDayCheckDetail.setKeeper2code(swStOutputDetail.getKeeper2code());
        //库管员2
        swStStockDayCheckDetail.setKeeper2name(swStOutputDetail.getKeeper2name());
        //起止号
        swStStockDayCheckDetail.setTicketNo(swStOutputDetail.getTicketNo());
    }

    /**
     * 新的出库修改处理
     * @param swStOutputDetail
     * @return
     */
    @Transactional
    public R updateOutputDetailNew(SwStOutputDetail swStOutputDetail) {
        String errorMessage = "更新之后会存在结存数量小于当前车票数量，不允许修改！";
        try {
            //更新之前的数据
            SwStOutputDetail oldData = super.getById(swStOutputDetail);
            //根据id获取相对应的结存数据
            SwStStockDayCheckDetail stockDayCheckDetail = sdcd.getById(swStOutputDetail.getStockdayid());

            //同时更新车票领用、车票借用与归还、车票销毁数据
            SwTkOutStockReceive swTkOutStockReceive = SpringContextHolder.getBean(SwTkOutStockReceive.class);
            //编辑时出库类型未变动的情况下只需要更改
            if(Objects.equals(swStOutputDetail.getOutGoingType(),oldData.getOutGoingType())){
                swTkOutStockReceive.updateTicketReceiveInfo(swStOutputDetail);
            }
            //编辑时出库类型有变动 需要先删除旧出库关联的再根据符合的出库类型进行新增
            else {
                //先删除旧的
                swTkOutStockReceive.delTicketReceiveInfo(oldData);
                //再根据新出库符合的出库类型进行新增
                swTkOutStockReceive.saveTicketReceiveInfo(swStOutputDetail);
            }

            //更新出库数据
            super.updateById(swStOutputDetail);
            //车票名称、库区、数量不变的情况下，直接更新车票金额和车票次数
            if(Objects.equals(swStOutputDetail.getTicketName(),oldData.getTicketName()) &&
                    Objects.equals(swStOutputDetail.getStockArea(),oldData.getStockArea()) &&
                    swStOutputDetail.getTicketNumber().equals(oldData.getTicketNumber())){

                SwStStockDayCheckDetail swStStockDayCheckDetail = new SwStStockDayCheckDetail();
                swStStockDayCheckDetail.setTicketPrice(swStOutputDetail.getTicketPrice());
                swStStockDayCheckDetail.setTicketTimes(swStOutputDetail.getTicketTimes());
                swStStockDayCheckDetail.setId(stockDayCheckDetail.getId());
                return R.ok(sdcd.updateById(swStStockDayCheckDetail));
            }
            //查询大于此ID的所有数据,结存数量统一处理
            List<SwStStockDayCheckDetail> list =
                    sdcd.list(Wrappers.<SwStStockDayCheckDetail>lambdaQuery()
                            .eq(SwStStockDayCheckDetail::getTicketName,oldData.getTicketName())
                            .eq(SwStStockDayCheckDetail::getStockArea,oldData.getStockArea())
                            .gt(SwStStockDayCheckDetail::getId,stockDayCheckDetail.getId()));
            //车票和库区未变动：
            if(Objects.equals(swStOutputDetail.getTicketName(),oldData.getTicketName()) && Objects.equals(swStOutputDetail.getStockArea(),oldData.getStockArea()) ){
                if(oldData.getTicketNumber()!=null){
                    //先找到要修改的数据进行修改
                    SwStStockDayCheckDetail swStStockDayCheckDetail = new SwStStockDayCheckDetail();
                    //新数量-旧数量
                    int diff = swStOutputDetail.getTicketNumber() - oldData.getTicketNumber();
                    //去掉限制，结存可以为负数
                    //if((stockDayCheckDetail.getSettleNumber()-diff)<0){
                    //    throw  new Exception(errorMessage);
                    //}
                    swStStockDayCheckDetail.setStorageNumber(swStOutputDetail.getTicketNumber());
                    //出库减
                    swStStockDayCheckDetail.setSettleNumber(stockDayCheckDetail.getSettleNumber()-diff);
                    swStStockDayCheckDetail.setId(stockDayCheckDetail.getId());

                    if(CollectionUtil.isNotEmpty(list)){
                        for (SwStStockDayCheckDetail stStockDayCheckDetail : list) {
                            //去掉限制，结存可以为负数
                            //if((stockDayCheckDetail.getSettleNumber()-diff)<0){
                            //     throw  new Exception(errorMessage);
                            //
                            //}
                            stStockDayCheckDetail.setSettleNumber(stStockDayCheckDetail.getSettleNumber()-diff);
                        }
                    }
                    list.add(swStStockDayCheckDetail);
                    sdcd.updateBatchById(list);
                }
            }
            //车票和库区有变动：删除匹配的数据，
            else {
                if(oldData.getTicketNumber()!=null){
                    int diff = oldData.getTicketNumber();
                    //修改时多出库，就直接加
                    if(CollectionUtil.isNotEmpty(list)){
                        for (SwStStockDayCheckDetail stStockDayCheckDetail : list) {
                            //去掉限制，结存可以为负数
                            //if((stockDayCheckDetail.getSettleNumber()+diff)<0){
                            //    throw  new Exception(errorMessage);
                            //}
                            stStockDayCheckDetail.setSettleNumber(stStockDayCheckDetail.getSettleNumber()+diff);
                        }
                        sdcd.updateBatchById(list);
                    }
                    //有变动，删除结存表数据
                    SwStStockDayCheckDetail swStStockDayCheckDetailOld = new SwStStockDayCheckDetail();
                    swStStockDayCheckDetailOld.setId(swStOutputDetail.getStockdayid());
                    sdcd.removeById(swStStockDayCheckDetailOld);

                    //根据车票名称和库区，找到最大的id号对应的结存数量
                    int settleNum = sdcd.getNewSettleNum(swStOutputDetail.getTicketName(), swStOutputDetail.getStockArea());
                    if((settleNum - swStOutputDetail.getTicketNumber())<0){
                        throw  new Exception(errorMessage);
                    }
                    SwStStockDayCheckDetail swStStockDayCheckDetail = new SwStStockDayCheckDetail();
                    //重新新增一条变动后的数据
                    String inputOrOutPutstorage = "出库";
                    //数量
                    swStStockDayCheckDetail.setStorageNumber(swStOutputDetail.getTicketNumber());
                    //结存数量-出库数量 = 新的结存数量。
                    swStStockDayCheckDetail.setSettleNumber(settleNum - swStOutputDetail.getTicketNumber());
                    //处理公共属性
                    setSwStStockDayCheckDetail(swStStockDayCheckDetail,swStOutputDetail,inputOrOutPutstorage);
                    swStStockDayCheckDetail.setOutputOrInputStockid(swStOutputDetail.getId());
                    swStStockDayCheckDetail.setOutputOrInputStockno(swStOutputDetail.getOutstockno());
                    sdcd.save(swStStockDayCheckDetail);
                    //新增之后需要同步更新入库表相对应的关联库存id
                    swStOutputDetail.setStockdayid(swStStockDayCheckDetail.getId());
                    super.updateById(swStOutputDetail);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            //设置手动回滚
            TransactionAspectSupport.currentTransactionStatus()
                    .setRollbackOnly();
            return R.failed(e.getMessage().equals(errorMessage) ? e.getMessage() : "系统错误请联系管理员！");
        }
        return R.ok();

    }

    /**
     * 车票出库操作和完善信息
     * @param swStOutputDetail
     * @return
     */
    @Transactional
    public R saveOrUpdateDetail(SwStOutputDetail swStOutputDetail) {
        String errorMessage = "更新之后会存在结存数量小于当前车票数量，不允许修改！";
        String errorMessage2 = "库存更新异常！";
        boolean issuccuess = true;
        //首先更新库存账
        SwStStockDayCheckDetail swStStockDayCheckDetail = new SwStStockDayCheckDetail();
        try {
            //根据车票名称和库区，找到最大的id号对应的结存数量
            int settleNum = sdcd.getNewSettleNum(swStOutputDetail.getTicketName(), swStOutputDetail.getStockArea());
            if((settleNum - swStOutputDetail.getTicketNumber())<0){
                throw  new Exception(errorMessage);
            }
            String outputstorage = "出库";
            setSwStStockDayCheckDetail(swStStockDayCheckDetail,swStOutputDetail,outputstorage);
            //更新库存量
            swStStockDayCheckDetail.setStorageNumber(swStOutputDetail.getTicketNumber());
            //结存数量-出库数量 = 新的结存数量。
            swStStockDayCheckDetail.setSettleNumber(settleNum - swStOutputDetail.getTicketNumber());
            swStStockDayCheckDetail.setOutputOrInputStockid(swStOutputDetail.getId());
            swStStockDayCheckDetail.setOutputOrInputStockno(swStOutputDetail.getOutstockno());
            if (!StringUtils.isEmpty(swStOutputDetail.getRemark())) {
                swStStockDayCheckDetail.setRemark(swStOutputDetail.getRemark());
            }
            issuccuess = sdcd.save(swStStockDayCheckDetail);
            if (!issuccuess) {
                issuccuess = false;
                throw  new Exception(errorMessage2);
            }
            //设置关联库存id
            swStOutputDetail.setStockdayid(swStStockDayCheckDetail.getId());
            issuccuess = issuccuess && super.updateById(swStOutputDetail);
            SwTkOutStockReceive swTkOutStockReceive = SpringContextHolder.getBean(SwTkOutStockReceive.class);
            issuccuess = issuccuess && swTkOutStockReceive.saveTicketReceiveInfo(swStOutputDetail);

        } catch (Exception e) {
            e.printStackTrace();
            //设置手动回滚
            TransactionAspectSupport.currentTransactionStatus()
                    .setRollbackOnly();
            return R.failed(e.getMessage().equals(errorMessage) || e.getMessage().equals(errorMessage2)? e.getMessage() : "系统错误请联系管理员！");
        }
        return R.ok(issuccuess);
    }
    /**
     * 旧的出库修改
     * @param swStOutputDetail
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateOutputDetail(SwStOutputDetail swStOutputDetail) {
        //更新之前的数据
        SwStOutputDetail oldData = super.getById(swStOutputDetail);
        //更新出库数据
        boolean issuccues = super.updateById(swStOutputDetail);
        //同时更新车票领用、车票借用与归还、车票销毁数据
        SwTkOutStockReceive swTkOutStockReceive = SpringContextHolder.getBean(SwTkOutStockReceive.class);
        boolean issuccuess = swTkOutStockReceive.updateTicketReceiveInfo(swStOutputDetail);
        if(Objects.equals(swStOutputDetail.getTicketName(),oldData.getTicketName()) && Objects.equals(swStOutputDetail.getStockArea(),oldData.getStockArea()) ){
            SwStStockDayCheckDetail stockDayCheckDetail = sdcd.getById(swStOutputDetail.getStockdayid());
            SwStStockDayCheckDetail swStStockDayCheckDetail = new SwStStockDayCheckDetail();
            if(oldData.getTicketNumber()!=null){
                int diff = swStOutputDetail.getTicketNumber()-oldData.getTicketNumber();
                swStStockDayCheckDetail.setStorageNumber(swStOutputDetail.getTicketNumber());
                swStStockDayCheckDetail.setSettleNumber(stockDayCheckDetail.getSettleNumber()+diff);
            }
            swStStockDayCheckDetail.setId(stockDayCheckDetail.getId());
            sdcd.updateById(swStStockDayCheckDetail);
            //更新结存最新的数据
            SwStStockDayCheckDetail stockDayCheckDetails = stStockDayCheckDetailMapper.getOutStockNewest(swStOutputDetail.getTicketName(), swStOutputDetail.getStockArea());
            if(stockDayCheckDetails!=null){
                if(!Objects.equals(stockDayCheckDetail.getId(),stockDayCheckDetails.getId())){
                    SwStStockDayCheckDetail swStStockDayCheckDetails = new SwStStockDayCheckDetail();
                    if(oldData.getTicketNumber()!=null){
                        int diff = swStOutputDetail.getTicketNumber()-oldData.getTicketNumber();
                        swStStockDayCheckDetails.setSettleNumber(stockDayCheckDetails.getSettleNumber()+diff);
                    }
                    swStStockDayCheckDetails.setId(stockDayCheckDetails.getId());
                    sdcd.updateById(swStStockDayCheckDetails);
                }
            }
        }else{
            //如果改变车票名称或者票区时更新结存最新的数据
            //更新车票名称或者票区修改后对应的最新的数据
            SwStStockDayCheckDetail stockDayCheckDetails = stStockDayCheckDetailMapper.getOutStockNewest(swStOutputDetail.getTicketName(), swStOutputDetail.getStockArea());
            if(stockDayCheckDetails!=null){
                SwStStockDayCheckDetail swStStockDayCheckDetails = new SwStStockDayCheckDetail();
                swStStockDayCheckDetails.setSettleNumber(stockDayCheckDetails.getSettleNumber()+swStOutputDetail.getTicketNumber());
                swStStockDayCheckDetails.setId(stockDayCheckDetails.getId());
                sdcd.updateById(swStStockDayCheckDetails);
            }
            //删除车票名称或者票区修改前的旧的数据
            SwStStockDayCheckDetail swStStockDayCheckDetail = sdcd.getById(oldData.getStockdayid());
            swStStockDayCheckDetail.setTicketType(swStOutputDetail.getTicketType());
            swStStockDayCheckDetail.setTicketName(swStOutputDetail.getTicketName());
            swStStockDayCheckDetail.setTicketTimes(swStOutputDetail.getTicketTimes());
            swStStockDayCheckDetail.setTicketPrice(swStOutputDetail.getTicketPrice());
            swStStockDayCheckDetail.setStockArea(swStOutputDetail.getStockArea());
            swStStockDayCheckDetail.setStorageNumber(swStOutputDetail.getTicketNumber());
            int diff = swStOutputDetail.getTicketNumber()-oldData.getTicketNumber();
            swStStockDayCheckDetail.setSettleNumber(swStStockDayCheckDetail.getSettleNumber()+diff);
            sdcd.updateById(swStStockDayCheckDetail);
            //如果改变车票名称或者票区时更新结存旧的数据
            SwStStockDayCheckDetail stockDayCheckDetail = stStockDayCheckDetailMapper.getOutStockNewest(oldData.getTicketName(), oldData.getStockArea());
            if(stockDayCheckDetail!=null){
                SwStStockDayCheckDetail swStStockDayCheckDetails1 = new SwStStockDayCheckDetail();
                swStStockDayCheckDetails1.setSettleNumber(stockDayCheckDetail.getSettleNumber()-swStOutputDetail.getTicketNumber());
                swStStockDayCheckDetails1.setId(stockDayCheckDetail.getId());
                sdcd.updateById(swStStockDayCheckDetails1);
            }
        }
        return issuccues&&issuccuess;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateById(SwStOutputDetail swStOutputDetail) {
        SwStStockDayCheckDetail swStStockDayCheckDetail = sdcd.getById(swStOutputDetail.getStockdayid());
        swStStockDayCheckDetail.setStorageNumber(swStOutputDetail.getTicketNumber());
        if (!StringUtils.isEmpty(swStOutputDetail.getRemark())){
            swStStockDayCheckDetail.setRemark(swStOutputDetail.getRemark());
        }
        //首先更新库存
        if (!sdcd.saveOrUpdate(swStStockDayCheckDetail)) {
            throw new RuntimeException("更新库存异常!");
        }
        //车票出库更新出库类型时同步更新3种出库类型
        SwTkOutStockReceive swTkOutStockReceive = SpringContextHolder.getBean(SwTkOutStockReceive.class);
        swTkOutStockReceive.updateTicketReceiveInfo(swStOutputDetail);
        //更新入库数据
        return super.updateById(swStOutputDetail);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean removeById(Serializable id) {
        //级联删除库存
        SwStOutputDetail SwStOutputDetail = super.getById(id);
        long stockdayid = SwStOutputDetail.getStockdayid();
        if (!sdcd.removeById(stockdayid)) {
            throw new RuntimeException("更新库存异常!");
        }
        //车票出库删除时同步删除的3种出库类型
        SwTkOutStockReceive swTkOutStockReceive = SpringContextHolder.getBean(SwTkOutStockReceive.class);
        swTkOutStockReceive.delTicketReceiveInfo(SwStOutputDetail);
        //删除出库数据
        return super.removeById(id);
    }

    private int getSettleNum(SwStOutputDetail swStOutputDetail) {
        int settleNum = 0;
        int outStorageNum = sdcd.getOutStorgeNum(swStOutputDetail.getTicketType(), swStOutputDetail.getStockArea());
        int inStorageNum = sdcd.getInStorgeNum(swStOutputDetail.getTicketType(), swStOutputDetail.getStockArea());
        if (outStorageNum == 0 && inStorageNum == 0) {
            settleNum = 0;
        } else if (outStorageNum == 0 && inStorageNum != 0) {
            settleNum = inStorageNum;
        } else {
            //统计最新库存量 如果尚未尚未出库过，则库存为入库数
            settleNum = sdcd.getSettleNum(swStOutputDetail.getTicketType(), swStOutputDetail.getStockArea());
        }
        return settleNum;
    }
    /**
     * 导出通过ids导出文件
     *
     * @param dataList      导出数据ids
     * @param response
     */
    public void exportByIds(List<SwStOuputDetailExcelDvo> dataList, HttpServletResponse response) {
        InputStream excelTemplateIs = null;
        if (CollectionUtil.isNotEmpty(dataList)) {

            try {
                response.setContentType("application/vnd.ms-excel");
                response.setCharacterEncoding("utf-8");
                final String fileName = URLEncoder.encode("车票出库", "UTF-8");
                response.setHeader("Content-disposition", "attachment;filename=" + fileName + System.currentTimeMillis() + ".xlsx");

                String[] titleStr = new String[]{"单号", "出库原因", "票种", "车票名称", "车票次数", "车票金额(票价)", "张数", "起号/止号", "车票有效期", "存放区域", "备注"};

                excelTemplateIs = this.getClass().getResourceAsStream("/static/excel/template/SwStOuputDetailExcelDvo.xlsx");

                ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream()).registerConverter(new LocalDateTimeConverter()).registerConverter(new LocalDateConverter()).withTemplate(excelTemplateIs).build();
                WriteSheet writeSheet = EasyExcel.writerSheet("sheet1").build();
                FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();
                excelWriter.fill(dataList, fillConfig, writeSheet);

                Map<String, Object> map = new HashMap<>();
                map.put("currMonth", DateUtils.format(new Date(),"yyyy年MM月dd日"));
                excelWriter.fill(map, writeSheet);
                excelWriter.finish();

            }  catch (Exception e) {
                e.printStackTrace();
                log.error("车票出库数据错误");
            } finally {
                if(excelTemplateIs != null){
                    try {
                        excelTemplateIs.close();
                    } catch (IOException ioe) {
                        ioe.printStackTrace();
                    }

                }
            }
        }

    }
    /**
     * 导出所有车票出库信息
     *
     * @param swOutExportExcelDTO
     * @param response
     */
    public void exportAll(SwOutExportExcelDTO swOutExportExcelDTO, HttpServletResponse response) {
        List<SwStOuputDetailExcelDvo> dataList = swOutExportExcelDTO.getSwStOutDetailExcelBean();
        InputStream excelTemplateIs = null;
        if (CollectionUtil.isNotEmpty(dataList)) {
            Map<Integer, SwPmTicketAreaDvo> swPmTicketAreaDvoMap = null;
            Map<String, SwPmTicketCardTypeParamDvo> swPmTicketCardTypeParamDvoMap = null;
            Map<String, SwPmTicketCardTypeDvo> swPmTicketCardTypeDvoMap = null;
            Map<String, SysDictItemDTO> sysDictItemDTOMap = null;
            //查询票区名称字典 - 库区分区
            List<SwPmTicketAreaDvo> swPmTicketAreaDvo = (List<SwPmTicketAreaDvo>) subwaySupportService.getAreaDict().getData();
            if (CollectionUtil.isNotEmpty(swPmTicketAreaDvo)){
                swPmTicketAreaDvo = JSONObject.parseArray(JSONObject.toJSONString(swPmTicketAreaDvo),SwPmTicketAreaDvo.class);
                swPmTicketAreaDvoMap = swPmTicketAreaDvo.stream().collect(Collectors.toMap(SwPmTicketAreaDvo::getId, Function.identity(), (bean1, bean2) -> bean1));
            }
            //车票名称
            List<SwPmTicketCardTypeParamDvo> swPmTicketCardTypeParamDvos = (List<SwPmTicketCardTypeParamDvo>) subwaySupportService.getParamByMain().getData();
            if (CollectionUtil.isNotEmpty(swPmTicketCardTypeParamDvos)){
                swPmTicketCardTypeParamDvos = JSONObject.parseArray(JSONObject.toJSONString(swPmTicketCardTypeParamDvos),SwPmTicketCardTypeParamDvo.class);
                swPmTicketCardTypeParamDvoMap = swPmTicketCardTypeParamDvos.stream().collect(Collectors.toMap(SwPmTicketCardTypeParamDvo::getSubEnName, Function.identity(), (bean1, bean2) -> bean1));
            }
            //票种
            List<SwPmTicketCardTypeDvo> swPmTicketCardTypeDvos = (List<SwPmTicketCardTypeDvo>)subwaySupportService.getCardTypeDict().getData();
            if (CollectionUtil.isNotEmpty(swPmTicketCardTypeDvos)){
                swPmTicketCardTypeDvos = JSONObject.parseArray(JSONObject.toJSONString(swPmTicketCardTypeDvos),SwPmTicketCardTypeDvo.class);
                swPmTicketCardTypeDvoMap = swPmTicketCardTypeDvos.stream().collect(Collectors.toMap(SwPmTicketCardTypeDvo::getMainEnName, Function.identity(), (bean1, bean2) -> bean1));
            }
            //入库类型
            List<SysDictItemDTO> sysDictItemDTOS = swOutExportExcelDTO.getSysDictItemBean();
            if (CollectionUtil.isNotEmpty(sysDictItemDTOS)){
                sysDictItemDTOMap = sysDictItemDTOS.stream().collect(Collectors.toMap(SysDictItemDTO::getValue, Function.identity(), (bean1, bean2) -> bean1));
            }
            for (SwStOuputDetailExcelDvo swStOuputDetailExcelDvo : dataList) {
                if (CollectionUtil.isNotEmpty(swPmTicketAreaDvoMap) && swPmTicketAreaDvoMap.containsKey(Integer.valueOf(swStOuputDetailExcelDvo.getStockArea()))){
                    swStOuputDetailExcelDvo.setStockArea(swPmTicketAreaDvoMap.get(Integer.valueOf(swStOuputDetailExcelDvo.getStockArea())).getTicketAreaName());
                }
                if (CollectionUtil.isNotEmpty(swPmTicketCardTypeParamDvoMap) && swPmTicketCardTypeParamDvoMap.containsKey(swStOuputDetailExcelDvo.getTicketName())){
                    swStOuputDetailExcelDvo.setTicketName(swPmTicketCardTypeParamDvoMap.get(swStOuputDetailExcelDvo.getTicketName()).getSubName());
                }
                if (CollectionUtil.isNotEmpty(swPmTicketCardTypeDvoMap) && swPmTicketCardTypeDvoMap.containsKey(swStOuputDetailExcelDvo.getTicketType())){
                    swStOuputDetailExcelDvo.setTicketType(swPmTicketCardTypeDvoMap.get(swStOuputDetailExcelDvo.getTicketType()).getMainName());
                }
                if (CollectionUtil.isNotEmpty(sysDictItemDTOMap) && sysDictItemDTOMap.containsKey(swStOuputDetailExcelDvo.getOutGoingType())){
                    swStOuputDetailExcelDvo.setOutGoingType(sysDictItemDTOMap.get(swStOuputDetailExcelDvo.getOutGoingType()).getLabel());
                }
            }
            try {
                response.setContentType("application/vnd.ms-excel");
                response.setCharacterEncoding("utf-8");
                final String fileName = URLEncoder.encode("车票出库", "UTF-8");
                response.setHeader("Content-disposition", "attachment;filename=" + fileName + System.currentTimeMillis() + ".xlsx");

                String[] titleStr = new String[]{"单号", "出库原因", "票种", "车票名称", "车票次数", "车票金额(票价)", "张数", "起号/止号", "车票有效期", "存放区域", "备注"};

                excelTemplateIs = this.getClass().getResourceAsStream("/static/excel/template/SwStOuputDetailExcelDvo.xlsx");

                ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream()).registerConverter(new LocalDateTimeConverter()).registerConverter(new LocalDateConverter()).withTemplate(excelTemplateIs).build();
                WriteSheet writeSheet = EasyExcel.writerSheet("sheet1").build();
                FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();
                excelWriter.fill(dataList, fillConfig, writeSheet);

                Map<String, Object> map = new HashMap<>();
                map.put("currMonth", DateUtils.format(new Date(),"yyyy年MM月dd日"));
                excelWriter.fill(map, writeSheet);
                excelWriter.finish();
            } catch (Exception e) {
                e.printStackTrace();
                log.error("车票出库数据错误");
            } finally {
                if (excelTemplateIs != null) {
                    try {
                        excelTemplateIs.close();
                    } catch (IOException ioe) {
                        ioe.printStackTrace();
                    }

                }
            }
        }

    }

}
